home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / utils / console / svgatext.3 / svgatext / SVGATextMode-1.3 / probe.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-03-06  |  7.7 KB  |  253 lines

  1. /*  SVGATextMode -- An SVGA textmode manipulation/enhancement tool
  2.  *
  3.  *  Copyright (C) 1995,1996  Koen Gadeyne
  4.  *
  5.  *  This program is free software; you can redistribute it and/or modify
  6.  *  it under the terms of the GNU General Public License as published by
  7.  *  the Free Software Foundation; either version 2 of the License, or
  8.  *  (at your option) any later version.
  9.  *
  10.  *  This program is distributed in the hope that it will be useful,
  11.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  *  GNU General Public License for more details.
  14.  *
  15.  *  You should have received a copy of the GNU General Public License
  16.  *  along with this program; if not, write to the Free Software
  17.  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18.  */
  19.  
  20.  
  21. /***
  22.  *** probe.c
  23.  ***
  24.  *** All kinds of probing fuctions (currently just the clock probe)
  25.  ***
  26.  *** Try to measure CURRENT pixel clock.
  27.  *** Should work on ANY VGA card, since it only uses standard VGA registers
  28.  ***
  29.  *** - No need to disable interrupts to be able to measure!
  30.  *** - Can give slightly inaccurate results on heavily loaded machines (but normally not VERY wrong)
  31.  *** - Due to wraparound in the usec counter (wraps at 1000000 usec), heavily loaded machines could show
  32.  ***   measurement "bins" at values _below_ one time the actual vertical sync interval.
  33.  ***   Bins at a multiple are normal, since a task-switch could make the clock probe miss 
  34.  ***   some (or many) V-interval events. If the probe is switched away for > 1 sec, the usec counter
  35.  ***   has wrapped around, and so an actual value of 1013425 usec between two measurements
  36.  ***   shows up at 13425 usec instead. This is the reason for the "glitches" in the measurements.
  37.  ***
  38.  *** There should even be a possibility to measure H-frequencies using input status 1 bit 0 (0x3DA, bit 0).
  39.  ***
  40.  ***/
  41.  
  42. #undef DBG_MEASURE 
  43.  
  44. #include <stdio.h>
  45. #include <string.h>
  46. #include <values.h>
  47. #include <signal.h>
  48. #include <stdlib.h>
  49. #include <unistd.h>
  50. #include <sys/types.h>
  51. #include <sys/time.h>
  52.  
  53. #ifndef DOS
  54. #  define UCLOCKS_PER_SEC 1000000
  55. #endif
  56. #define URATIO (1000000.0/(float)UCLOCKS_PER_SEC)
  57.  
  58. #ifndef DOS
  59. #  include <asm/io.h>
  60. #endif
  61.  
  62. #include "misc.h"
  63. #include "vga_prg.h"
  64. #include "file_ops.h"
  65. #include "wait_vsync.h"
  66. #include "messages.h"
  67. #include "modedata.h"
  68.  
  69.  
  70. /*
  71.  * The Clock probe. Given the hor. and vert. REAL TOTAL screen size, it returns the pixel clock in MHz
  72.  * 
  73.  * 'REAL' means you have to input the total screen width (which is read from VGA regs in CHARS)
  74.  * multiplied by the font size (8 or 9).
  75.  *
  76.  * NOTE: this function ASSUMES it has the rights to read VGA register STATUS1 !
  77.  *
  78.  * Should work on ANY VGA card, since it only uses standard VGA registers
  79.  *
  80.  * - No need to disable interrupts to be able to measure! (the probe in the X-server does, because it doesn't use timers). 
  81.  * - Can give slightly inaccurate results on heavily loaded machines (but normally not VERY wrong)
  82.  * - Due to unexplained "glitches" in the vertical sync register, some timing attempts go wrong.
  83.  *   this is detected in the program, and it tries again.
  84.  *   Does anyone know WHY those glitches are there, and how to circumvent them?
  85.  * - has the tendency to over-estimate the clock rate by about 0.1 MHz. No real clue why... (or is it just on MY machine?)
  86.  *
  87.  * There should even be a possibility to measure H-frequencies using input status 1 bit 0 (STATUS1, bit 0).
  88.  *
  89.  */
  90.  
  91. #define REALLY_SLOW_IO
  92.  
  93. /* number of frames to count for timing measurement */
  94. #define NFRAMES    100
  95.  
  96.  
  97. /* number sorting function for sort() */
  98. static int compar(long* a, long* b)
  99. {
  100.   return(*a - *b);
  101. }
  102.  
  103.                    
  104. #define M_RETRY      3            /* maximum number of retries */
  105. #define TIME_BAND    5            /* in usec, defines the time-band size used for building a histogram */ 
  106. #define VALID_MEASR  NFRAMES*2/3  /* this number of measurements must be valid, or measurement will be bad */
  107.  
  108.  
  109. bool measure_pixclock(modestruct* m)
  110.  
  111. /* This assumes the rest of the mode structure already  contains the correct data
  112.  * This routine only adds the pixel clock and H/V frequencies to the structure
  113.  * (and possibly a remark)
  114.  */
  115.  
  116. {
  117. #ifndef DOS
  118.   struct timeval tv;
  119. #endif
  120.   int i;
  121.   long measure[NFRAMES+1];
  122.   volatile long center;  /* "volatile" gets around a bug in GCC 2.7.0 that causes it's value to be lost */
  123.   double scanrate;
  124.   int retries=0;
  125.   double av;
  126.   long current;
  127.   volatile int num, centernum;
  128.   
  129.   int hsize = (m->mode_line.HTotal/8)*m->mode_line.FontWidth;
  130.   int vsize = m->mode_line.VTotal;
  131.   
  132.   int (*compfunc) ();
  133.   compfunc=compar;
  134.  
  135.   if (!safe_wait_vsync())
  136.   {
  137.     m->mode_line.pixelClock = 0;
  138.     m->mode_line.hfreq = 0;
  139.     m->mode_line.vfreq = 0;
  140.     m->remarks |= MSG_CLOCKPROBE_FAILED;
  141.     return FALSE;
  142.   }
  143.  
  144.   /* measure */
  145.   do
  146.   {
  147.     /*** Try to do a measurement ***/
  148.     PDEBUG(("Measurement attempt #%d\n",retries));
  149.     waitframe;    /* synchronize */
  150.  
  151.     /* this short measurement loop should be optimized heavily, or even written in assembler */
  152.     for (i=0; i<NFRAMES+1; i++)
  153.     {
  154.       waitframe;    /* measure */
  155. #ifndef DOS
  156.       gettimeofday(&tv, NULL); 
  157.       measure[i] = tv.tv_usec;  /* this will go wrong if we are task-switched out for > 1 sec ... */
  158. #else
  159.       /* DOS DJGPP also has gettimeofday(), but resolution is only 1/18 sec. So we use uclock() */ 
  160.       measure[i] = uclock();
  161. #endif
  162.     }
  163.     /* end of measurement loop */ 
  164.  
  165.     av = 0;
  166.     /*** convert absolute timer intervals to relative intervals ***/
  167.     for (i=0; i<NFRAMES; i++)
  168.     {
  169. #ifdef DBG_MEASURE
  170.       printf(" %ld", measure[i]);
  171. #endif
  172.       measure[i] = measure[i+1] - measure[i];
  173.  
  174.       /* UNIX: usec counter wraps around at 1 sec (1000000 usec)
  175.        *
  176.        * DJGPP/DOS: the usec timer does not wrap around at 1 sec.
  177.        *            It is a 64-bit counter, so it NEVER produces a negative difference result
  178.        */
  179. #ifndef DOS
  180.       if (measure[i]<0) measure[i] += 1000000;
  181. #endif
  182.     }
  183.     
  184. #ifdef DBG_MEASURE
  185.       printf("\n");
  186. #endif
  187.     
  188.     /*** sort measurements ***/
  189.     qsort(measure, NFRAMES, sizeof(long), compfunc);
  190.  
  191.     /*** find value at peak of histogram ***/
  192.     /*** Use that to filter out values out of bounds ***/
  193.     PDEBUG(("URATIO = %1.3f\n", URATIO));
  194.     current = measure[0];
  195.     center = current + TIME_BAND/2;
  196.     centernum = 0;
  197.     i = 0;
  198.     do
  199.     {
  200.       num = 0;
  201.       while ((abs(measure[i]-current) < TIME_BAND) && (i<NFRAMES))
  202.       {
  203.         num++; i++;
  204.       }
  205.       if (num > centernum)
  206.       {
  207.         centernum = num;
  208.         center = current + TIME_BAND/2;
  209.       }
  210.       if (num>0)
  211.       {
  212.         PDEBUG(("Time slot: %1.0f..%1.0f usec, number: %d\n",\
  213.                  ((float)current)*URATIO, ((float)current)*URATIO+TIME_BAND, num));
  214.       }
  215.       current += TIME_BAND;
  216.     } while (i<NFRAMES);
  217.  
  218.     PDEBUG(("Center = %1.0f usec\n", ((float)center)*URATIO));
  219.  
  220.     /*** Use histogram peak as center value, filter out values out of bounds ***/
  221.     av = 0; num = 0;
  222.     for (i=0; i<NFRAMES; i++)
  223.     {
  224.       if (abs(measure[i]-center) < (TIME_BAND*3))
  225.       {
  226.         av+=measure[i];
  227.         num++;
  228.       }
  229.     }
  230.     av /= num;
  231.     
  232.     retries++;
  233.     PDEBUG(("Measurement: valid measurements: %ld/%d\n", num, NFRAMES));
  234.   }
  235.   while ( (retries<M_RETRY) && (num<VALID_MEASR) );
  236.  
  237.   scanrate = UCLOCKS_PER_SEC/av;
  238.  
  239.   PDEBUG(("average framerate (from valid measurements only) = %5.1f usec\n", av * URATIO));
  240.   if (num < VALID_MEASR)
  241.   {
  242.     m->remarks |= MSG_CLOCK_MEASUREMENTS;
  243.     m->valid_measurements = num*100/NFRAMES;
  244.   }
  245.  
  246.   PDEBUG(("Real total H = %d , total V = %d\n", hsize, vsize));
  247.  
  248.   m->mode_line.pixelClock = (scanrate * hsize * vsize) / 1000;
  249.   m->mode_line.hfreq = ((m->mode_line.pixelClock*1000)/m->mode_line.HTotal) * 8 / m->mode_line.FontWidth;
  250.   m->mode_line.vfreq = (m->mode_line.hfreq*1000)/m->mode_line.VTotal;
  251.   return TRUE;
  252. }
  253.